package org.yu.team2023.flashdays.blockentity;

import lombok.Getter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yu.team2023.flashdays.ITreasureXP;
import org.yu.team2023.flashdays.ModBlockEntities;
import org.yu.team2023.flashdays.ModItemTags;
import org.yu.team2023.flashdays.TreasureData;
import org.yu.team2023.flashdays.item.TreasureCurios;
import org.yu.team2023.flashdays.item.TreasureUpgradeItem;
import org.yu.team2023.flashdays.net.FlashNet;
import org.yu.team2023.flashdays.net.TreasureUpgradeRequestPackage;

import java.util.ArrayList;
import java.util.List;

public class TreasureUpgradeEntity extends BlockEntity {
    @Getter
    protected final ItemStackHandler inputSlots;
    @Getter
    protected final ItemStackHandler outputSlots;


    public TreasureUpgradeEntity(BlockPos pPos, BlockState pBlockState) {
        super(ModBlockEntities.BlockEntities.TREASURE_UPGRADE_ENTITY.get(), pPos, pBlockState);
        this.inputSlots = new ItemStackHandler(4) {
            @Override
            protected void onContentsChanged(int slot) {
                TreasureUpgradeEntity.this.setChangedNotUpdate();
                expCheck();
            }

            @Override
            public boolean isItemValid(int slot, @NotNull ItemStack stack) {
                if (slot == 0) return stack.is(ModItemTags.CURIOS_TREASURES);
                return slot < this.getSlots() && stack.getItem() instanceof ITreasureXP;
            }
        };
        this.outputSlots = new ItemStackHandler(4) {
            @Override
            protected void onContentsChanged(int slot) {
                TreasureUpgradeEntity.this.setChangedNotUpdate();
            }

            @Override
            public boolean isItemValid(int slot, @NotNull ItemStack stack) {
                return slot < this.getSlots() && stack.getItem() instanceof ITreasureXP;
            }
        };

    }

    private void setChangedNotUpdate() {
        if (level != null)
            level.blockEntityChanged(worldPosition);
    }

    @Override
    public @NotNull
    <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
        if (cap.equals(ForgeCapabilities.ITEM_HANDLER)) {
            if (side == Direction.DOWN)
                return LazyOptional.of(() -> outputSlots).cast();
            else return LazyOptional.of(() -> inputSlots).cast();
        }
        return LazyOptional.empty();
    }

    @Override
    protected void saveAdditional(@NotNull CompoundTag pTag) {
        super.saveAdditional(pTag);
        pTag.put("inputs", inputSlots.serializeNBT());
        pTag.put("outputs", outputSlots.serializeNBT());
    }

    @Override
    public void load(@NotNull CompoundTag pTag) {
        super.load(pTag);
        this.inputSlots.deserializeNBT(pTag.getCompound("inputs"));
        this.outputSlots.deserializeNBT(pTag.getCompound("outputs"));
        expCheck();
    }

    boolean hasExp = false;

    private void expCheck() {
        boolean find = false;
        for (int i = 1; i < inputSlots.getSlots(); i++) {
            if (!inputSlots.getStackInSlot(i).isEmpty()) {
                hasExp = true;
                find = true;
                break;
            }
        }
        if (!find) hasExp = false;
    }

    public boolean canUpgrade() {
        var treasureStack = inputSlots.getStackInSlot(0);
        if(!outputEmpty())return false;
        if (treasureStack.isEmpty() || !hasExp) return false;
        if (treasureStack.getItem() instanceof TreasureCurios) {
            var treasureData = TreasureCurios.getData(treasureStack);
            return treasureData != null && treasureData.getLevel() < treasureData.getQuality().getMaxLevel();
        }
        return false;
    }

    public void sendUpgradeRequest() {
        FlashNet.channel.sendToServer(new TreasureUpgradeRequestPackage(worldPosition));
    }
    public boolean outputEmpty(){
        for (int i = 0; i < outputSlots.getSlots(); i++) {
            if (!outputSlots.getStackInSlot(i).isEmpty()) return false;
        }
        return true;
    }
    public void upgradeOnServer() {
        if (canUpgrade()) {
            var treasureStack = inputSlots.getStackInSlot(0);
            if (treasureStack.getItem() instanceof TreasureCurios) {
                var treasureData = TreasureCurios.getData(treasureStack);
                if (treasureData != null && treasureData.getLevel() < treasureData.getQuality().getMaxLevel()) {
                    int allXp = 0;
                    for (int i = 1; i < inputSlots.getSlots(); i++) {
                        allXp += readStackXP(inputSlots.getStackInSlot(i));
                    }

                    int remainXp = treasureData.upgrade(allXp);

                    treasureData.save(treasureStack);
                    for (int i = 1; i < inputSlots.getSlots(); i++) {
                        inputSlots.setStackInSlot(i,ItemStack.EMPTY);
                    }
                    var remain = TreasureUpgradeItem.xpToStack(remainXp);
                    for (ItemStack stack : remain) {
                        ItemStack s = ItemHandlerHelper.insertItemStacked(outputSlots, stack.copy(), false);
                        if (!s.isEmpty()) {
                            ItemEntity entity = new ItemEntity(level, worldPosition.getX(), worldPosition.getY() + 0.5, worldPosition.getZ(), s);
                            level.addFreshEntity(entity);
                        }
                    }
                }
            }
        }
    }

    private int readStackXP(ItemStack stack) {
        if (stack.isEmpty()) return 0;
        if (stack.getItem() instanceof ITreasureXP xp) {
            return xp.getTreasureXp(stack);
        }
        return 0;
    }

    public boolean hasAttribute() {
        var treasureStack = inputSlots.getStackInSlot(0);
        if (treasureStack.isEmpty()) return false;
        if (treasureStack.getItem() instanceof TreasureCurios) {
            var treasureData = TreasureCurios.getData(treasureStack);
            return treasureData != null;
        }
        return false;
    }


    public List<? extends Component> getAttributeTooltipsWithLevel() {
        var treasureStack = inputSlots.getStackInSlot(0);
        if (treasureStack.isEmpty()) return List.of();
        if (treasureStack.getItem() instanceof TreasureCurios) {
            var treasureData = TreasureCurios.getData(treasureStack);
            if (treasureData != null) {
                ArrayList<Component> list = new ArrayList<>();
                list.add(Component.translatable("tip.flashdays.upgradeCount", treasureData.getLevel()));
                list.add(treasureStack.getDisplayName());
                return treasureData.getAttributesTooltip(list);
            }
        }
        return List.of();
    }

    public Component getUpgradeProgress() {
        TreasureData data=TreasureData.safeCreate(inputSlots.getStackInSlot(0));
        if(data!=null)
            return data.getUpgradeProgress();
        return Component.empty();
    }
}
